﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DefensiveShield.Properties;

namespace DefensiveShield
{

    #region Structures

    public class FileSystemListItem
    {
        public string Name { get; set; }
        public string Secrecy { get; set; }
        public string Type { get; set; }
        public string Registered { get; set; }
        public ContextMenu Menu { get; set; }
    }

    public class IntegrityCheckListItem
    {
        public string Name { get; set; }
        public string Integrity { get; set; }
    }

    #endregion

    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        //private List<Window> _windows;
        public OsSession Session;
        public string Username;

        #region CurrentDirectory

        private string _currentDirectory;
        public string CurrentDirectoryWithSlash
        {
            get
            {
                if (string.IsNullOrEmpty(_currentDirectory) || _currentDirectory == "\\")
                {
                    return "";
                }
                if (_currentDirectory.EndsWith("\\"))
                {
                    return  _currentDirectory;
                }
                return (new DirectoryInfo(_currentDirectory)).FullName + "\\";
            }
            set { _currentDirectory = string.IsNullOrEmpty(value) || value == "\\" ? "" : value; }
        }

        public string CurrentDirectoryWithoutSlash
        {
            get
            {
                return string.IsNullOrEmpty(_currentDirectory) || _currentDirectory == "\\"
                    ? ""
                    : (new DirectoryInfo(_currentDirectory)).FullName;
            }
            set
            {
                _currentDirectory = string.IsNullOrEmpty(value) || value == "\\" ? "" : value;
            }
        }

        #endregion    

        #region ContextMenuItems

        public MenuItem DeleteMenuItem;
        public MenuItem RegisterMenuItem;
        public MenuItem SystemElementPropertiesMenuItem;
        public MenuItem AddToIntegrityCheckMenuItem;
        public MenuItem RemoveFromIntegrityCheckMenuItem;

        #endregion

        #region ContextMenuClickHandlers

        private void DeleteSystemElement(object sender, RoutedEventArgs e)
        {
            var fileSystemListItem = DirectotyEntriesList.SelectedItem as FileSystemListItem;
            if (fileSystemListItem != null)
            {
                var errorCode = OS.DeleteItem(Session, CurrentDirectoryWithSlash + fileSystemListItem.Name);
                if (errorCode != ErrorCodes.NoError)
                {
                    ShowErrorMessage(errorCode);
                    return;
                }
            }
            ShowDirectoryEntries(CurrentDirectoryWithSlash);
            ClearErrorMessage();
        }

        private void ShowSystemElementProperties(object sender, RoutedEventArgs e)
        {
            var fileSystemListItem = DirectotyEntriesList.SelectedItem as FileSystemListItem;
            if (fileSystemListItem != null)
            {
                ///////////////////////////////////////////////////////////////////
            }
        }

        private void RemoveFileFromIntegrityCheck(object sender, RoutedEventArgs e)
        {
            var fileSystemListItem = DirectotyEntriesList.SelectedItem as FileSystemListItem;
            if (fileSystemListItem != null)
            {
                var errorCode = OS.RemoveFileFromIntegrityChecker(CurrentDirectoryWithSlash + fileSystemListItem.Name);
                if (errorCode != ErrorCodes.NoError)
                {
                    ShowErrorMessage(errorCode);
                    return;
                }
            }
            ClearErrorMessage();
            ShowDirectoryEntries(CurrentDirectoryWithSlash);
            UpdateIntegrityCheckingList();
        }

        private void AddFileToIntegrityCheck(object sender, RoutedEventArgs e)
        {
            var fileSystemListItem = DirectotyEntriesList.SelectedItem as FileSystemListItem;
            if (fileSystemListItem != null)
            {
                var errorCode = OS.AddFileToIntegrityChecker(CurrentDirectoryWithSlash + fileSystemListItem.Name);
                if (errorCode != ErrorCodes.NoError)
                {
                    ShowErrorMessage(errorCode);
                    ShowDirectoryEntries(CurrentDirectoryWithSlash);
                    return;
                }
            }
            ClearErrorMessage();
            ShowDirectoryEntries(CurrentDirectoryWithSlash);
            UpdateIntegrityCheckingList();
        }

        private void RegisterSystemElement(object sender, RoutedEventArgs e)
        {
            var fileSystemListItem = DirectotyEntriesList.SelectedItem as FileSystemListItem;
            if (fileSystemListItem != null)
            {
                var errorCode = OS.RegisterFileSystemObject(Session, CurrentDirectoryWithSlash + fileSystemListItem.Name);
                fileSystemListItem.Registered = "Зарегистрирован";
                if (errorCode != ErrorCodes.NoError)
                {
                    ShowErrorMessage(errorCode);
                    ShowDirectoryEntries(CurrentDirectoryWithSlash);
                    return;
                }
            }
            ShowDirectoryEntries(CurrentDirectoryWithSlash);
            ClearErrorMessage();
        }


        #endregion

        //DONE: Повесить вызов OS.ShutdownOs на закрытие приложения
        public MainWindow()
        {
            var error = OS.InitializeOS();
            if (error != ErrorCodes.NoError)
            {
                ShowErrorMessage(error);
                Application.Current.Shutdown(1);
            }
            InitializeComponent();
            InitializeGrafon();
            InitializeContextMenus();
            ShowStart();
        }

        #region Initialize

        private void ShowFileSystem()
        {
            SystemGrid.Visibility = Visibility.Visible;
            CreateAdminGrid.Visibility = Visibility.Hidden;
            EnterSystemGrid.Visibility = Visibility.Hidden;
        }

        public void ShowStart()
        {
            SystemGrid.Visibility = Visibility.Hidden;
            if (OS.AdministratorName == null)
            {
                CreateAdminGrid.Visibility = Visibility.Visible;
                EnterSystemGrid.Visibility = Visibility.Hidden;
            }
            else
            {
                CreateAdminGrid.Visibility = Visibility.Hidden;
                EnterSystemGrid.Visibility = Visibility.Visible;
            }
        }

        public void InitializeGrafon()
        {
            Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
            Application.Current.MainWindow = this;
            Session = OS.CreateOsSession();

            UserSecrecyComboBox.ItemsSource =
                (from object secrecy in Enum.GetValues(typeof (Secrecy)) select ((Secrecy) secrecy).ToRussianString());
            GroupRightsDirectoryComboBox.ItemsSource = OtherRightsDirectoryComboBox.ItemsSource =
                GroupRightsFileComboBox.ItemsSource = OtherRightsFileComboBox.ItemsSource =
                    (from object rights in Enum.GetValues(typeof (Rights)) select ((Rights) rights).ToRussianString());
        }

        public void InitializeContextMenus()
        {
            DeleteMenuItem = new MenuItem() {Header = "Удалить"};
            DeleteMenuItem.Click += DeleteSystemElement;

            SystemElementPropertiesMenuItem = new MenuItem() {Header = "Изменить параметры"};
            SystemElementPropertiesMenuItem.Click += ShowSystemElementProperties;
            
            RegisterMenuItem = new MenuItem() { Header = "Зарегистрировать в системе" };
            RegisterMenuItem.Click += RegisterSystemElement;

            AddToIntegrityCheckMenuItem = new MenuItem() {Header = "Добавить в список проверки на целостность"};
            AddToIntegrityCheckMenuItem.Click += AddFileToIntegrityCheck;

            RemoveFromIntegrityCheckMenuItem = new MenuItem() {Header = "Удалить из списка проверки на целостность"};
            RemoveFromIntegrityCheckMenuItem.Click += RemoveFileFromIntegrityCheck;
        }

        #endregion     

        #region WindowEventHandlers

        private void CreateAdminButton_Click(object sender, RoutedEventArgs e)
        {
            if (AdminNameBox.Text == "")
            {
                ShowErrorMessage("Введите имя учётной записи администратора!");
                return;
            }
            OS.CreateAdministrator(AdminNameBox.Text, AdminPasswordBox.Password);
            CreateAdminGrid.Visibility = Visibility.Hidden;
            EnterSystemGrid.Visibility = Visibility.Visible;
            AdminNameBox.Text = AdminPasswordBox.Password = "";
            ClearErrorMessage();
        }

        private void EnterSystemButton_Click(object sender, RoutedEventArgs e)
        {
            if (UserListBox.SelectedIndex == -1)
            {
                ShowErrorMessage("Выберите пользователя!");
                return;
            }
            Username = UserListBox.Items[UserListBox.SelectedIndex] as string;

            var retVal = Session.Login(Username, UserPasswordBox.Password);
            UserPasswordBox.Password = "";
            if (Username == OS.AdministratorName)
            {
                SystemGrid.Resources["AdminPanelHeight"] = new GridLength(28);
                SystemGrid.Resources["PathNSearchPanelHeight"] = new GridLength(42);
            }
            else
            {
                SystemGrid.Resources["AdminPanelHeight"] = new GridLength(0);
                SystemGrid.Resources["PathNSearchPanelHeight"] = new GridLength(70);
            }
            if (retVal != ErrorCodes.NoError)
            {
                ShowErrorMessage(retVal);
                return;
            }
            if (Username != null && OS.Users.ContainsKey(Username))
                ShowDirectoryEntries(OS.Users[Username].HomeDirectory);
            UserListBox.SelectedIndex = -1;
            EnterSystemGrid.Visibility = Visibility.Hidden;
            SystemGrid.Visibility = Visibility.Visible;
            LogoutButton.Visibility = Visibility.Visible;

            InterfaceButton_Click(null, null);
            ClearErrorMessage();
        }

        private void DirectoryEntriesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var fileView = DirectotyEntriesList.SelectedItem as FileSystemListItem;
            if (fileView != null)
            {
                FilePathTextBox.Text = CurrentDirectoryWithSlash + fileView.Name;
                FilePathTextBox.Opacity = 1;
            }
            else
            {
                FilePathTextBox.Text = "Путь";
                FilePathTextBox.Opacity = 0.6;
            }
            ClearErrorMessage();
        }

        private void DirectoryEntriesList_KeyDown(object sender, KeyEventArgs e)
        {
            var key = e.Key;
            switch (key)
            {
                case Key.Enter:
                    OpenSystemElement(DirectotyEntriesList.SelectedItem);
                    break;
                case Key.Back:
                    GotoParentDirectory();
                    break;
                case Key.F5:
                    ShowDirectoryEntries(CurrentDirectoryWithSlash);
                    break;
            }
        }

        private void FsSearchTextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            FsSearchTextBox.Text = "";
            FsSearchTextBox.Opacity = 1;
            ClearErrorMessage();
        }

        private void FsSearchTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            FsSearchTextBox.Text = "Поиск";
            FsSearchTextBox.Opacity = 0.6;
        }

        private void FsItem_DoubleClick(object sender, MouseButtonEventArgs e)
        {
            var listViewItem = sender as ListViewItem;
            if (listViewItem != null) OpenSystemElement(listViewItem.Content);
        }

        private void FsParentDirectoryButton_Click(object sender, RoutedEventArgs e)
        {
            GotoParentDirectory();
        }

        private void FSRefreshButton_Click(object sender, RoutedEventArgs e)
        {
            ShowDirectoryEntries(CurrentDirectoryWithSlash);
            ClearErrorMessage();
        }

        private void InterfaceButton_Click(object sender, RoutedEventArgs e)
        {
            InterfaceButton.Background = Application.Current.Resources["OnMouseOverColor"] as Brush;
            UserSettingsButton.Background =
                IntegrityCheckButton.Background = Application.Current.Resources["GrafonColor"] as Brush;
            RibbonGrid.Visibility = Visibility.Visible;
            DirectotyEntriesList.Visibility = Visibility.Visible;
            UserSettingsGrid.Visibility = Visibility.Hidden;
            IntegrityCheckingGrid.Visibility = Visibility.Hidden;
        }

        private void IntegrityCheckButton_Click(object sender, RoutedEventArgs e)
        {
            IntegrityCheckButton.Background = Resources["OnMouseOverColor"] as Brush;
            UserSettingsButton.Background =
                InterfaceButton.Background = Application.Current.Resources["GrafonColor"] as Brush;
            RibbonGrid.Visibility = Visibility.Hidden;
            DirectotyEntriesList.Visibility = Visibility.Hidden;
            UserSettingsGrid.Visibility = Visibility.Hidden;
            IntegrityCheckingGrid.Visibility = Visibility.Visible;
        }

        private void UserSettingsButton_Click(object sender, RoutedEventArgs e)
        {
            UserSettingsButton.Background = Application.Current.Resources["OnMouseOverColor"] as Brush;
            InterfaceButton.Background =
                IntegrityCheckButton.Background = Application.Current.Resources["GrafonColor"] as Brush;
            RibbonGrid.Visibility = Visibility.Hidden;
            DirectotyEntriesList.Visibility = Visibility.Hidden;
            UserSettingsGrid.Visibility = Visibility.Visible;
            IntegrityCheckingGrid.Visibility = Visibility.Hidden;
            UserList.ItemsSource = new List<string>(OS.Users.Keys);
        }

        private void LogoutButton_Click(object sender, RoutedEventArgs e)
        {
            Session.LogOut();
            SystemGrid.Visibility = Visibility.Hidden;
            EnterSystemGrid.Visibility = Visibility.Visible;
            LogoutButton.Visibility = Visibility.Hidden;
            ClearErrorMessage();
        }

        private void UserList_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var userName = UserList.SelectedItem as string;
            if (userName == null)
            {
                UserNameTextBox.IsEnabled = true;

                UserNameTextBox.Text = "";
                GroupNumberTextBox.Text = "";
                UserSecrecyComboBox.SelectedItem = null;
                UserSecrecyComboBox.SelectedItem = null;
                GroupRightsDirectoryComboBox.SelectedItem = null;
                OtherRightsDirectoryComboBox.SelectedItem = null;
                GroupRightsFileComboBox.SelectedItem = null;
                OtherRightsFileComboBox.SelectedItem = null;
                return;
            }

            UserNameTextBox.IsEnabled = false;

            var user = OS.Users[userName];
            UserNameTextBox.Text = user.UserName;
            UserPasswordTextBox.Text = "";
            GroupNumberTextBox.Text = user.GroupName;
            UserSecrecyComboBox.SelectedIndex = (int)user.SecrecyNum;
            GroupRightsDirectoryComboBox.SelectedIndex = (int)user.GroupRightsDirectory;
            OtherRightsDirectoryComboBox.SelectedIndex = (int)user.OthersRightsDirectory;
            GroupRightsFileComboBox.SelectedIndex = (int)user.GroupRightsFile;
            OtherRightsFileComboBox.SelectedIndex = (int)user.OthersRightsFile;
        }

        private void CreateUserButton_Click(object sender, RoutedEventArgs e)
        {
            UserList.SelectedItem = null;
        }

        private void SaveUserSettingsButton_Click(object sender, RoutedEventArgs e)
        {
            var userName = UserList.SelectedItem as string;

            if (userName == null)
            {
                OS.CreateUser(UserNameTextBox.Text, UserPasswordTextBox.Text, GroupNumberTextBox.Text,
                    (Secrecy)UserSecrecyComboBox.SelectedIndex, (Rights)GroupRightsDirectoryComboBox.SelectedIndex,
                    (Rights)OtherRightsDirectoryComboBox.SelectedIndex, (Rights)GroupRightsFileComboBox.SelectedIndex,
                    (Rights)OtherRightsFileComboBox.SelectedIndex);
            }
            else
            {
                var userPassport = new UserPassport
                {
                    UserName = userName,
                    GroupName = GroupNumberTextBox.Text,
                    SecrecyNum = (Secrecy)UserSecrecyComboBox.SelectedIndex,
                    PasswdHash = OS.Hash(UserPasswordTextBox.Text),
                    GroupRightsDirectory = (Rights)GroupRightsDirectoryComboBox.SelectedIndex,
                    OthersRightsDirectory = (Rights)OtherRightsDirectoryComboBox.SelectedIndex,
                    GroupRightsFile = (Rights)GroupRightsFileComboBox.SelectedIndex,
                    OthersRightsFile = (Rights)OtherRightsFileComboBox.SelectedIndex
                };
                OS.Users[userPassport.UserName] = userPassport;
            }
            UserList.ItemsSource = new List<string>(OS.Users.Keys);
        }

        private void EnterSystemGrid_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            UserListBox.ItemsSource = new List<string>(OS.Users.Keys);
        }

        private void DeleteUserButton_Click(object sender, RoutedEventArgs e)
        {
            var userName = UserList.SelectedItem as string;
            if (userName != null && OS.Users.ContainsKey(userName))
            {
                if (userName == OS.AdministratorName)
                {
                    ShowErrorMessage(ErrorCodes.AttemptToDeleteAdministrator);
                    return;
                }
                OS.Users.Remove(userName);
            }
            UserList.ItemsSource = new List<string>(OS.Users.Keys);
            ClearErrorMessage();
        }

        private void DirectotyEntriesList_MouseDown(object sender, MouseButtonEventArgs e)
        {
            // ReSharper disable once PossibleNullReferenceException
            (sender as ListView).SelectedItem = null;
            ClearErrorMessage();
            FilePathTextBox.Text = CurrentDirectoryWithoutSlash;
            FilePathTextBox.Opacity = 1;
        }

        private void UserPasswordTextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            var textBox = sender as TextBox;
            if (textBox != null) textBox.Text = "";
        }

        private void FilePathTextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            ClearErrorMessage();
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            OS.ShutdownOS();
        }

        #endregion

        #region GrafonUpdate

        public void ShowDirectoryEntries(string newCurrentDirectory)
        {

            var fileNamesList = OS.GetDirectorySubElements(Session, newCurrentDirectory);
            if (fileNamesList == null)
            {
                ShowErrorMessage("Папка не существует или доступ приложения к ней запрещён");
                return;
            }
            CurrentDirectoryWithSlash = newCurrentDirectory;
            var fileList = new List<FileSystemListItem>();
            foreach (var file in fileNamesList)
            {
                var cm = new List<MenuItem>();
                var fileInfo = new FileInfo(file);
                if (OS.Files.ContainsKey(file))
                {
                    cm.Add(DeleteMenuItem);

                    if (Session.UserName == OS.AdministratorName)
                    {
                        cm.Add(SystemElementPropertiesMenuItem);

                        if (OS.GetFileType(file) != FileType.Directory)
                        {
                            cm.Add(OS.FileIntegrity.ContainsKey(file)
                                ? RemoveFromIntegrityCheckMenuItem
                                : AddToIntegrityCheckMenuItem);
                        }
                    }

                    var secretFile = OS.Files[file];
                    fileList.Add(new FileSystemListItem()
                    {
                        Name = fileInfo.Name == "" ? fileInfo.FullName : fileInfo.Name,
                        Secrecy = secretFile.SecrecyNum.ToRussianString(),
                        Type = secretFile.FileTypeNum.ToRussianString(),
                        Registered = "Зарегистрирован",
                        Menu = cm.Any() ? new ContextMenu() { ItemsSource = cm } : null
                    });
                }
                else if (fileInfo.Attributes != FileAttributes.Hidden && fileInfo.Extension != ".sys")
                {
                    if (OS.GetFileType(file) != FileType.Other)
                    {
                        cm.Add(RegisterMenuItem);
                    }

                    fileList.Add(new FileSystemListItem()
                    {
                        Name = string.IsNullOrEmpty(fileInfo.Name) ? fileInfo.FullName : fileInfo.Name,
                        Secrecy = Secrecy.NonSecret.ToRussianString(),
                        Type = OS.GetFileType(file).ToRussianString(),
                        Registered = "Не зарегистрирован",
                        Menu = cm.Any() ? new ContextMenu() { ItemsSource = cm } : null
                    });
                }
            }
            DirectotyEntriesList.ItemsSource = fileList;
            DirectotyEntriesList.SelectedItem = null;
            ClearErrorMessage();
            ResetFocus();
            FilePathTextBox.Text = CurrentDirectoryWithoutSlash;
            FilePathTextBox.Opacity = 1;
        }

        public void UpdateIntegrityCheckingList()
        {
            var fileList = OS.FileIntegrity.Select(file => new IntegrityCheckListItem()
            {
                Name = file.Key, Integrity = file.Value
            });
            IntergityCheckList.ItemsSource = fileList;
            IntergityCheckList.SelectedItem = null;
            ClearErrorMessage();
        }

        private void ShowErrorMessage(string message)
        {
            MessageBox.Show(message);
//             ErrorMessage.Background = Brushes.Tomato;
//             ErrorMessage.BorderBrush = Brushes.Tomato;
//             ErrorMessage.Text = message;
        }

        private void ShowErrorMessage(ErrorCodes errorCode)
        {
            MessageBox.Show(errorCode.ToRussianString());
//             ErrorMessage.Background = Brushes.Tomato;
//             ErrorMessage.BorderBrush = Brushes.Tomato;
//             ErrorMessage.Text = errorCode.ToRussianString();
        }

        private void ClearErrorMessage()
        {
//             ErrorMessage.Background = Application.Current.Resources["GrafonColor"] as Brush;
//             ErrorMessage.BorderBrush = Application.Current.Resources["GrafonColor"] as Brush;
//             ErrorMessage.Text = "";
        }
        private void ResetFocus()
        {
            var scope = FocusManager.GetFocusScope(this);
            FocusManager.SetFocusedElement(scope, DirectotyEntriesList);
            Keyboard.Focus(DirectotyEntriesList);
        }

        #endregion

        #region LogicalFunctions
        private void OpenSystemElement(object fileViewItem)
        {
            if (fileViewItem == null) return;
            var fileView = fileViewItem as FileSystemListItem;
            if (fileView == null) return;
            var fileName = CurrentDirectoryWithSlash + fileView.Name;
            var fileType = OS.GetFileType(fileName);
            switch (fileType)
            {
                case FileType.Directory:
                    ShowDirectoryEntries(fileName);
                    break;
                case FileType.TextFile:
                {
                    var text = OS.OpenSecretFile(Session, fileName);
                    switch (text)
                    {
                        case null:
                            ShowErrorMessage(ErrorCodes.MandatoryAccessDenied);
                            break;
                        default:
                            (new TextEditor(Session, fileName, text)).Show();
                            break;
                    }
                }
                    break;
                case FileType.Other:
                case FileType.Executable:
                    OS.ExecuteFile(Session, fileName);
                    break;
            }
        }

        private void GotoParentDirectory()
        {
            var fileName = OS.GetParentDirectory(Session, CurrentDirectoryWithoutSlash);
            var fileType = OS.GetFileType(fileName);
            if (fileType == FileType.Directory)
            {
                ShowDirectoryEntries(fileName);
            }
            ResetFocus();
        }

        #endregion

        

    }

}
